Skip to content

Add support for sending header values to Quepid - #482

Open
matt-bernhardt wants to merge 2 commits into
mainfrom
use-660
Open

matt-bernhardt wants to merge 2 commits into
mainfrom
use-660

Conversation

@matt-bernhardt

@matt-bernhardt matt-bernhardt commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

This adds support for specifying the format token via the request header, in addition to via a querystring parameter. This is an addition, rather than a replacement, because at the moment Quepid is configured to use the querystring option - and I'd like not to break that via a hard cutover.

I'm not sure right now whether we'll want to follow this up with a PR to remove the querystring option (once Quepid has been reconfigured). There may be value in continuing to use the querystring for local or in-browser use.

Ticket: https://mitlibraries.atlassian.net/browse/USE-660

To confirm this integration: I've updated the experimental search endpoint within our Quepid instance to point at this review app, specifying the format token via a request header. You should be able to run the mapper wizard within Quepid and confirm that this integration now works as intended.

Developer

Accessibility
  • ANDI or WAVE has been run in accordance to our guide.
  • This PR contains no changes to the view layer.
  • New issues flagged by ANDI or WAVE have been resolved.
  • New issues flagged by ANDI or WAVE have been ticketed (link in the Pull Request details above).
  • No new accessibility issues have been flagged.
New ENV
  • All new ENV is documented in README.
  • All new ENV has been added to Heroku Pipeline, Staging and Prod.
  • ENV has not changed.
Approval beyond code review
  • UXWS/stakeholder approval has been confirmed.
  • UXWS/stakeholder review will be completed retroactively.
  • UXWS/stakeholder review is not needed.
Additional context needed to review

E.g., if the PR includes updated dependencies and/or data
migration, or how to confirm the feature is working.

Code Reviewer

Code
  • I have confirmed that the code works as intended.
  • Any CodeClimate issues have been fixed or confirmed as
    added technical debt.
Documentation
  • The commit message is clear and follows our guidelines
    (not just this pull request message).
  • The documentation has been updated or is unnecessary.
  • New dependencies are appropriate or there were no changes.
Testing
  • There are appropriate tests covering any new functionality.
  • No additional test coverage is required.

@coveralls

coveralls commented Oct 30, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 41711839038

Coverage increased (+0.001%) to 98.424%

Details

  • Coverage increased (+0.001%) from the base build.
  • Patch coverage: 4 of 4 lines across 1 file are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 1903
Covered Lines: 1873
Line Coverage: 98.42%
Coverage Strength: 1854.86 hits per line

💛 - Coveralls

@mitlib
mitlib temporarily deployed to timdex-ui-pi-use-660-2ete2ib6k October 30, 2026 21:25 Inactive
@mitlib
mitlib temporarily deployed to timdex-ui-pi-use-660-2ete2ib6k November 2, 2026 20:29 Inactive
@qltysh

qltysh Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

❌ 5 blocking issues (5 total)

Tool Category Rule Count
rubocop Style Line is too long. [121/120] 2 ❌
rubocop Style Prefer single-quoted strings when you don't need string interpolation or special symbols. 2 ❌
rubocop Style Incorrect formatting, autoformat by running qlty fmt. 1 ❌

@qltysh one-click actions:

  • Auto-fix formatting (qlty fmt && git push)

Comment thread app/controllers/search_controller.rb Resolved
Comment thread app/controllers/search_controller.rb Resolved
@mitlib
mitlib temporarily deployed to timdex-ui-pi-use-660-2ete2ib6k November 2, 2026 20:43 Inactive
Comment thread app/controllers/search_controller.rb Resolved
Comment thread app/controllers/search_controller.rb Resolved
quepid_ua = 'Quepid/1.0 (Web Scraper)'
ClimateControl.modify FORMAT_TOKEN: secret_value do
mock_timdex_search_with_hits(10)
get "/results?q=test&format=json", headers: { 'HTTP_USER_AGENT' => quepid_ua, 'HTTP_FORMAT_TOKEN' => secret_value }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 2 issues:

1. Line is too long. [121/120] [rubocop:Layout/LineLength]


2. Prefer single-quoted strings when you don't need string interpolation or special symbols. [rubocop:Style/StringLiterals]

** Why are these changes being introduced:

We want to allow Quepid to provide the format token via a request
header, rather than via the query parameters.

** Relevant ticket(s):

* https://mitlibraries.atlassian.net/browse/use-660

** How does this address that need:

This updates the search controller to check either the params or the
request header for the format token, preferring the headers first.

** Document any side effects to this change:

This adds pretty minimal test coverage for the request header for now,
but these tests will be re-written more heavily when we go back through
and remove support for query parameters (assuming we take that step -
it might be good to keep that support around for browser-based
debugging)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Blank header tokens can cause server errors instead of 401 responses, while valid header tokens fail to preserve the existing throttle bypass.

2 open issues
What changed in this PR

Adds header-based token authentication for Quepid’s JSON search requests while retaining query-parameter support.

Changes:

  • Accepts Format-Token headers, preferring nonblank header values over query parameters.
  • Adds tests for successful header authentication and rejection of invalid tokens or missing server configuration.
File Description
test/​controllers/​search_controller_test.rb Adds header-token authentication coverage alongside existing parameter tests.
app/​controllers/​search_controller.rb Reads and validates tokens from headers or query parameters.

Review effort: Balanced

Comment thread app/controllers/search_controller.rb Outdated
return false unless ENV.fetch('FORMAT_TOKEN', '').present?

false
request.headers.key?('HTTP_FORMAT_TOKEN') || params.key?(:format_token)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've applied the change to the search controller to the rack attack configuration, and updated the tests for the format token bypass to confirm that both options are still valid (as well as what the precedence is should tokens arrive via both pathways).

# a boolean.
def valid_token?
return true if ActiveSupport::SecurityUtils.secure_compare(params[:format_token], ENV.fetch('FORMAT_TOKEN', ''))
candidate = request.headers['HTTP_FORMAT_TOKEN'].presence || params[:format_token]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the search controller in a different way, using .presence within the format_tokens_defined? method as well as within the validity check. This prevents the need for a guard clause on candidate.blank?, as it stops valid_token? from being called in the first place. I've added a test on lines 2001-2013 to confirm the intended behavior (red-green refactor FTW, I think)

Changes here are:
- protect against blank format_tokens
- extend support for request headers to rack attack integration
- add tests for both rack attack and controller to clarify precedence
  between the header and params (header should govern if both are supplied)
@mitlib
mitlib temporarily deployed to timdex-ui-pi-use-660-2ete2ib6k November 3, 2026 20:21 Inactive

ClimateControl.modify(FORMAT_TOKEN: secret_value, FEATURE_BOT_DETECTION: 'true') do
mock_timdex_search_with_hits(10)
get "/results?q=test&format=json", headers: { 'HTTP_FORMAT_TOKEN' => secret_value, 'HTTP_USER_AGENT' => quepid_ua }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 2 issues:

1. Line is too long. [121/120] [rubocop:Layout/LineLength]


2. Prefer single-quoted strings when you don't need string interpolation or special symbols. [rubocop:Style/StringLiterals]

@JPrevost JPrevost self-assigned this Nov 9, 2026

This branch was previously deployed

1 inactive deployment
timdex-ui-pi-use-660-2ete2ib6k — ef71e301 Deployed Nov 3, 2026 by mitlib
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants